// ignore_for_file: constant_identifier_names

import 'dart:collection';
import 'dart:convert';

import 'package:eq/src/core.dart';

enum LexerStatus {
  INITIAL_STATUS, //初始状态
  COMMENT_STATUS, //注释状态
  COMMENT_STATUS1, //多行注释状态
  NUM_STATUS, //整形状态
  String_STATUS, //字符串
  String_STATUS1, //转义字符
  IDENTIFIER_STATUS, //标识符
  REG_STATUS, //正则表达式
}

enum TokenType {
  Invalid,
  INT_LITERAL,
  DOUBLE_LITERAL,
  STRING_LITERAL,
  COMPLEX_LITERAL,
  IDENTIFIER,
  GLOBAL,
  FUNCTION,
  IF,
  ELSE,
  ELSIF,
  WHILE,
  FOR,
  RETURN_T,
  BREAK,
  CONTINUE,
  NULL_T,
  LP,
  RP,
  LC,
  RC,
  SEMICOLON,
  COMMA,
  ASSIGN_T,
  LOGICAL_AND,
  LOGICAL_OR,
  EQ,
  NE,
  GT,
  GE,
  LT,
  LE,
  LB,
  RB,
  ADD,
  SUB,
  MUL,
  DIV,
  MOD,
  COLON,
  TRUE_T,
  FALSE_T,
  SWITCH,
  CASE,
  DEFAULT,
  TRY,
  CATCH,
  FINALLY,
  IMPORT,
  DOT,
  AS,
  EXCLAMATION,
  MOD_ASSIGN_T,
  BIT_AND_ASSIGN_T,
  BIT_AND,
  DECREMENT,
  INCREMENT,
  MUL_ASSIGN_T,
  ADD_ASSIGN_T,
  SUB_ASSIGN_T,
  DIV_ASSIGN_T,
  BIT_XOR_ASSIGN_T,
  DOT_MUL,
  DOT_DIV,
  BIT_XOR,
  BIT_OR_ASSIGN_T,
  BIT_OR,
  BIT_NOT,
  CONST,
  REGEXP_LITERAL,
  END_OF_FILE
}

Map<String, TokenType> keyWord = {
  "function": TokenType.FUNCTION,
  "if": TokenType.IF,
  "else": TokenType.ELSE,
  "elsif": TokenType.ELSIF,
  "switch": TokenType.SWITCH,
  "case": TokenType.CASE,
  "default": TokenType.DEFAULT,
  "while": TokenType.WHILE,
  "for": TokenType.FOR,
  "return": TokenType.RETURN_T,
  "continue": TokenType.CONTINUE,
  "break": TokenType.BREAK,
  "null": TokenType.NULL_T,
  "true": TokenType.TRUE_T,
  "false": TokenType.FALSE_T,
  "try": TokenType.TRY,
  "catch": TokenType.CATCH,
  "finally": TokenType.FINALLY,
  "import": TokenType.IMPORT,
  "const": TokenType.CONST,
  "as": TokenType.AS
};

//保存每个Token式子的信息
class TokenExpression {
  String? identifier;
  String? error;
  late TokenType tokenType;
  Expression expression = Expression(ExpressionType.Invalid_EXPRESSION);
  LinkedList<Parameter> parameterList = LinkedList();
  LinkedList<ArgumentList> argumentList = LinkedList();
  Statement statement = Statement();
  Block block = Block();
  LinkedList<Statement> statementList = LinkedList();
  LinkedList<Expression> expressionList = LinkedList();
  LinkedList<CaseList> caseList = LinkedList();
  late CaseList case_;
  LinkedList<Elsif> elsifList = LinkedList();
  late Elsif elsif;
  LinkedList<IdentifierList> identifierList = LinkedList();
  // static Array array;
  TokenExpression() {
    tokenType = TokenType.Invalid;
  }
  TokenExpression.tokenType(this.tokenType);
  @override
  String toString() {
    return tokenType.toString();
  }
}

TokenExpression getToken() {
  List<int> currentToken = List.empty(growable: true);
  LexerStatus status = LexerStatus.INITIAL_STATUS; //词法分析器状态机
  TokenExpression tokenExpression =
      TokenExpression.tokenType(TokenType.Invalid);
  String temp;
  int step = 0; //控制步骤
  while (true) {
    if (currentpos >= codeLen) {
      tokenExpression.tokenType = TokenType.END_OF_FILE;
      if (currentToken.isNotEmpty) {
        tokenExpression.tokenType = TokenType.Invalid;
        tokenExpression.error = "语法错误";
      } else {
        tokenExpression.expression.rowNum = currentposH;
        tokenExpression.expression.colNum = currentposL + 1;
      }
      return tokenExpression;
    }
    currentChar = code[currentpos];
    currentpos++;
    currentposL++;

    //换行符
    if (currentChar == 0x0A) {
      currentposL = 0;
      currentposH++;

      if (status == LexerStatus.COMMENT_STATUS) {
        status = LexerStatus.INITIAL_STATUS;
      }
      continue;
    }
    switch (status) {
      case LexerStatus.INITIAL_STATUS:
        step = 0;
        break;
      case LexerStatus.IDENTIFIER_STATUS:
        if (currentChar == 0x5F ||
            (currentChar >= 0x41 && currentChar <= 0x5A) ||
            (currentChar >= 0x61 && currentChar <= 0x7A) ||
            (currentChar >= 0x30 && currentChar <= 0x39)) {
          currentToken.add(currentChar);
          continue;
        } else {
          status = LexerStatus.INITIAL_STATUS;
          temp = utf8.decode(currentToken);
          currentpos--;
          currentposL--;
          //关键字
          if (keyWord.containsKey(temp)) {
            tokenExpression.tokenType = keyWord[temp]!;
            if (tokenExpression.tokenType == TokenType.GLOBAL) {
              tokenExpression.tokenType = TokenType.Invalid;
              tokenExpression.error = "[$temp]:此处不能使用关键词";
            }
          } else {
            tokenExpression.identifier = temp;
          }
          return tokenExpression;
        }
      case LexerStatus.COMMENT_STATUS1:
        if (currentChar == 0x2A && code[currentpos] == 0x2F) {
          status = LexerStatus.INITIAL_STATUS;
          currentpos++;
          currentposL++;
        }
        continue;
      case LexerStatus.COMMENT_STATUS:
        continue;
      case LexerStatus.NUM_STATUS:

        ///数字和小数点
        if ((currentChar >= 0x30 && currentChar <= 0x39) ||
            currentChar == 0x2E) {
          currentToken.add(currentChar);
          temp = utf8.decode(currentToken);
          if ((step == 1) && (currentChar != 0x30 && currentChar != 0x31)) {
            tokenExpression.tokenType = TokenType.Invalid;
            tokenExpression.error = "[$temp]: 数字字面量错误";
            return tokenExpression;
          }

          continue;
        } else if ((currentChar == 0x42 || currentChar == 0x62) &&
            (currentToken.length == 1) &&
            (currentToken[0] == 0x30)) {
          currentToken.add(currentChar);
          step = 1;
          continue;
        } else if ((currentChar == 0x58 || currentChar == 0x78) &&
            (currentToken.length == 1) &&
            (currentToken[0] == 0x30)) {
          currentToken.add(currentChar);
          step = 2;
          continue;
        } else if ((step == 2) &&
            ((currentChar >= 0x41 && currentChar <= 0x46) ||
                (currentChar >= 0x61 && currentChar <= 0x66))) {
          currentToken.add(currentChar);
          continue;
        } else {
          status = LexerStatus.INITIAL_STATUS;
          temp = utf8.decode(currentToken);
          Expression expression = Expression(ExpressionType.Invalid_EXPRESSION);
          if (temp.contains('.')) {
            if (temp.endsWith('.') ||
                (temp.split('.').length > 2) ||
                (step != 0)) {
              tokenExpression.tokenType = TokenType.Invalid;
              tokenExpression.error = "[$temp]: 数字字面量错误";
              return tokenExpression;
            }

            expression.type = ExpressionType.DOUBLE_EXPRESSION;
            expression.doublevalue = double.parse(temp);
            tokenExpression.tokenType = TokenType.DOUBLE_LITERAL;
          } else {
            expression.type = ExpressionType.INT_EXPRESSION;
            if (step == 0) {
              expression.intvalue = int.parse(temp);
            } else if (step == 1) {
              expression.intvalue =
                  int.parse(temp.replaceRange(0, 2, ""), radix: 2);
            } else if (step == 2) {
              expression.intvalue =
                  int.parse(temp.replaceRange(0, 2, ""), radix: 16);
            }
          }
          if ((currentChar == 0x69) || (currentChar == 0x6A)) {
            //i,j
            expression.type = ExpressionType.COMPLEX_EXPRESSION;
            tokenExpression.tokenType = TokenType.COMPLEX_LITERAL;
          } else {
            currentpos--;
            currentposL--;
          }
          tokenExpression.expression = expression;
          return tokenExpression;
        }
      case LexerStatus.String_STATUS:

        ///设计字串模板{}
        if (currentChar == 0x5C) {
          //转义字符
          status = LexerStatus.String_STATUS1;
          continue;
        }
        if (currentChar == 0x22) {
          status = LexerStatus.INITIAL_STATUS;
          Expression expression = Expression(ExpressionType.Invalid_EXPRESSION);
          expression.type = ExpressionType.STRING_EXPRESSION;
          expression.stringvalue = utf8.decode(currentToken);
          tokenExpression.expression = expression;
          return tokenExpression;
        }
        currentToken.add(currentChar);
        continue;
      case LexerStatus.String_STATUS1: //转义字符
        switch (currentChar) {
          case 0x61:
            currentToken.add(0x07);
            break;
          case 0x62:
            currentToken.add(0x08);
            break;
          case 0x66:
            currentToken.add(0x0C);
            break;
          case 0x6E:
            currentToken.add(0x0a);
            break;
          case 0x72:
            currentToken.add(0x0D);
            break;
          case 0x74:
            currentToken.add(0x09);
            break;
          case 0x76:
            currentToken.add(0x0B);
            break;
          default:
            currentToken.add(currentChar);
        }
        status = LexerStatus.String_STATUS;
        continue;
      case LexerStatus.REG_STATUS:
        if (currentChar == 0x5C) {
          //转义字符
          currentToken.add(code[currentpos]);
          currentpos++;
          continue;
        }
        if (currentChar == 0x27) {
          status = LexerStatus.INITIAL_STATUS;
          Expression expression = Expression(ExpressionType.Invalid_EXPRESSION);
          expression.type = ExpressionType.REGEXP_EXPRESSION;
          expression.stringvalue = utf8.decode(currentToken);
          tokenExpression.expression = expression;
          return tokenExpression;
        }
        currentToken.add(currentChar);
        continue;
      default:
    }

    tokenExpression.expression.rowNum = currentposH;
    tokenExpression.expression.colNum = currentposL;
    //空格制表符处理
    if (currentChar == 0x20 || currentChar == 0x09) {
      continue;
    }

    //数字处理[0-9]+\.[0-9]+
    if (currentChar >= 0x30 && currentChar <= 0x39) {
      status = LexerStatus.NUM_STATUS;
      tokenExpression.tokenType = TokenType.INT_LITERAL;
      currentToken.add(currentChar);
      continue;
    }
    //标识符处理 关键字在处理完后识别 [A-Za-z_][A-Za-z_0-9]*
    if (currentChar == 0x5F ||
        (currentChar >= 0x41 && currentChar <= 0x5A) ||
        (currentChar >= 0x61 && currentChar <= 0x7A)) {
      status = LexerStatus.IDENTIFIER_STATUS;
      tokenExpression.tokenType = TokenType.IDENTIFIER;
      currentToken.add(currentChar);
      continue;
    }
    switch (currentChar) {
      case 0x0D:
        break;
      case 0x21: //!
        if (code[currentpos] == 0x3D) {
          //!=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.NE;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.EXCLAMATION;
        return tokenExpression;
      case 0x22: //字符串，允许换行[扩展]
        status = LexerStatus.String_STATUS;
        tokenExpression.tokenType = TokenType.STRING_LITERAL;
        break;
      case 0x23: //注释处理#
        status = LexerStatus.COMMENT_STATUS;
        break;
      case 0x24: //全局变量$
        if (code[currentpos] == 0x5F ||
            (code[currentpos] >= 0x41 && code[currentpos] <= 0x5A) ||
            (code[currentpos] >= 0x61 && code[currentpos] <= 0x7A)) {
          status = LexerStatus.IDENTIFIER_STATUS;
          tokenExpression.tokenType = TokenType.GLOBAL;
        } else {
          tokenExpression.tokenType = TokenType.Invalid;
          temp = utf8.decode(currentToken);
          tokenExpression.error = "[$temp]:全局变量引用错误";
          return tokenExpression;
        }
        break;
      case 0x25: //%
        if (code[currentpos] == 0x3D) {
          //%=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.MOD_ASSIGN_T;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.MOD;
        return tokenExpression;
      case 0x26: //&
        if (code[currentpos] == 0x26) {
          //&&
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.LOGICAL_AND;
          return tokenExpression;
        } else if (code[currentpos] == 0x3D) {
          //&=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.BIT_AND_ASSIGN_T;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.BIT_AND;
        return tokenExpression;
      case 0x27: //'
        status = LexerStatus.REG_STATUS;
        tokenExpression.tokenType = TokenType.REGEXP_LITERAL;
        break;
      case 0x28: //(
        tokenExpression.tokenType = TokenType.LP;
        return tokenExpression;
      case 0x29: //)
        tokenExpression.tokenType = TokenType.RP;
        return tokenExpression;
      case 0x2A: //*
        if (code[currentpos] == 0x3D) {
          //*=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.MUL_ASSIGN_T;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.MUL;
        return tokenExpression;
      case 0x2B: //+
        if (code[currentpos] == 0x3D) {
          //+=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.ADD_ASSIGN_T;
          return tokenExpression;
        } else if (code[currentpos] == 0x2B) {
          //+=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.INCREMENT;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.ADD;
        return tokenExpression;
      case 0x2C: //,
        tokenExpression.tokenType = TokenType.COMMA;
        return tokenExpression;
      case 0x2D: //-
        if (code[currentpos] == 0x3D) {
          //-=
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.SUB_ASSIGN_T;
          return tokenExpression;
        } else if (code[currentpos] == 0x2D) {
          //+=
          currentpos++;
          currentposL++;
          tokenExpression.tokenType = TokenType.DECREMENT;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.SUB;
        return tokenExpression;
      case 0x2E: //.
        if (code[currentpos] == 0x2A) {
          //.*
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.DOT_MUL;
          return tokenExpression;
        } else if (code[currentpos] == 0x2F) {
          //./
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.DOT_DIV;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.DOT;
        return tokenExpression;
      case 0x2F: // /
        if (code[currentpos] == 0x3D) {
          // /=
          //<=
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.DIV_ASSIGN_T;
          return tokenExpression;
        } else if (code[currentpos] == 0x2A) {
          currentposL++;
          currentpos++;
          status = LexerStatus.COMMENT_STATUS1;
          break;
        }
        tokenExpression.tokenType = TokenType.DIV;
        return tokenExpression;
      case 0x3A: //:
        tokenExpression.tokenType = TokenType.COLON;
        return tokenExpression;
      case 0x3B: //;
        tokenExpression.tokenType = TokenType.SEMICOLON;
        return tokenExpression;
      case 0x3C: //<
        if (code[currentpos] == 0x3D) {
          //<=
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.LE;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.LT;
        return tokenExpression;
      case 0x3D: //=
        if (code[currentpos] == 0x3D) {
          //==
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.EQ;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.ASSIGN_T;
        return tokenExpression;
      case 0x3E: //>
        if (code[currentpos] == 0x3D) {
          //>=
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.GE;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.GT;
        return tokenExpression;
      // case 0x3F://?
      //   return TokenExpression.tokenType(TokenType.LT);
      // case 0x40://@
      //   return TokenExpression.tokenType(TokenType.LT);
      case 0x5B: //[
        tokenExpression.tokenType = TokenType.LB;
        return tokenExpression;
      // case 0x5C://\
      //   return TokenExpression.tokenType(TokenType.RB);
      case 0x5D: //]
        tokenExpression.tokenType = TokenType.RB;
        return tokenExpression;
      case 0x5E: //^
        if (code[currentpos] == 0x3D) {
          //^=
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.BIT_XOR_ASSIGN_T;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.BIT_XOR;
        return tokenExpression;
      // case 0x60://`
      //   return TokenExpression.tokenType(TokenType.LT);
      case 0x7B: //{
        tokenExpression.tokenType = TokenType.LC;
        return tokenExpression;
      case 0x7C: //|
        if (code[currentpos] == 0x7C) {
          //||
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.LOGICAL_OR;
          return tokenExpression;
        } else if (code[currentpos] == 0x3D) {
          //|=
          currentposL++;
          currentpos++;
          tokenExpression.tokenType = TokenType.BIT_OR_ASSIGN_T;
          return tokenExpression;
        }
        tokenExpression.tokenType = TokenType.BIT_OR;
        return tokenExpression;
      case 0x7D: //}
        tokenExpression.tokenType = TokenType.RC;
        return tokenExpression;

      case 0x7E: //~
        tokenExpression.tokenType = TokenType.BIT_NOT;
        return tokenExpression;
      default: //是不识别的字符
        currentToken.add(currentChar);
        tokenExpression.error = "[${currentChar.toString()}] 不识别的字符";
        return tokenExpression;
    }
  }
}
